/*
    Modified from The Loki Library
    Modified by : 2013 darkcat

    Copyright (c) 2001 by Andrei Alexandrescu

    This code accompanies the book:
    Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design 
        Patterns Applied". Copyright (c) 2001. Addison-Wesley.
    Permission to use, copy, modify, distribute and sell this software for any 
        purpose is hereby granted without fee, provided that the above copyright 
        notice appear in all copies and that both that copyright notice and this 
        permission notice appear in supporting documentation.
    The author or Addison-Welsey Longman make no representations about the 
        suitability of this software for any purpose. It is provided "as is" 
        without express or implied warranty.
*/

#pragma once

// nx...
#include "config/general.h"
// type logical operators
#include "type/typetools.h"

//////////////////////////////////////////////////////////////////////////
NX_BEG
//////////////////////////////////////////////////////////////////////////

/*
    Get the conversion of two classes
*/

template <typename T, typename U>
class Conversion
{
private:
    static type::yes_t check(U);
    static type::not_t check(...);

public:
    NX_PROPERTY(bool, ext, nx_is_yes(check(T())));
    NX_PROPERTY(bool, sam, false);
    NX_PROPERTY(bool, rev, ext && Conversion<U, T>::ext);
};

template <typename T>
class Conversion<T, T>
{
public:
    NX_PROPERTY(bool, ext, true);
    NX_PROPERTY(bool, sam, true);
    NX_PROPERTY(bool, rev, true);
};

#define nx_is_convertible(...) \
    nx::Conversion<__VA_ARGS__>::ext
#define nx_is_same(...) \
    nx::Conversion<__VA_ARGS__>::sam

/*
    Get the inheritance of two classes
*/

template <typename T, typename U>
struct SuperSub : 
    type::Judge<nx_is_convertible(const U*, const T*) && 
               !nx_is_same       (const T*, const void*) && 
               !nx_is_same       (const T , const U)>
{};

template <>
struct SuperSub<void, void> : 
    type::Judge<false>
{};

template <typename T>
struct SuperSub<T, void> : 
    type::Judge<false>
{};

template <typename U>
struct SuperSub<void, U> : 
    type::Judge<false>
{};

#define nx_is_supsub(...) \
    nx_bool(nx::SuperSub<__VA_ARGS__>)

//////////////////////////////////////////////////////////////////////////
NX_END
//////////////////////////////////////////////////////////////////////////
